# -*- coding: utf-8 -*-

from plugmgr import plugin

__all__ = ["events"]

class handlersQueue:
    ''' like dict, but sorted '''
    def __init__(self):
        self.order = []
        self.handlers = {}
        self.counter = 0
        self.__getitem__ = self.handlers.__getitem__
    def __repr__(self):
        return '<handlersQueue: {%s}>'%(', '.join(': '.join((str(i),repr(self.handlers[i]))) for i in self.order))
    def keys(self):
        return self.order
    def __delitem__(self,item):
        self.order.remove(item)
        del self.handlers[item]
    def push(self,value):
        self.counter += 1
        self.order.append(self.counter)
        self.handlers[self.counter] = value
        return self.counter
    def unshift(self,value):
        self.counter += 1
        self.order = [self.counter]+self.order
        self.handlers[self.counter] = value
        return self.counter
    def pop(self):
        item = order[-1]
        result = self[item]
        del self[item]
        return result
    def shift(self):
        item = order[0]
        result = self[item]
        del self[item]
        return result

class events(plugin):
    ''' Плагин предоставляет возможность оранизовывать генерацию и обработку событий среди других плагинов. '''
    requires = []
    events = {}
    def __init__(self, bot):
        self.bot = bot
    def registerEvent(self,name):
        ''' Регистрация события '''
        try:             self.events[name]
        except KeyError: self.events[name] = handlersQueue()
        else:            raise KeyError, 'Event %s is already registered!'%name
    def removeEvent(self,name):
        ''' Удаление события и всех его обработчиков '''
        for i in self.events[name].keys():
            del self.events[name][i]
        del self.events[name]
    def registerHandler(self,event,f,priority=False):
        '''
        Регистрация обработчика для события.
        Параметр priority задаёт характер регистрации: если True, то обработчик будет вызван раньше уже зарегистрированных, в противном случае позже всех.
        Если обработчик меняет данные, передаваемые следующим обработчикам, то он должен их вернуть с помощью return. Если в дальнейшей обработке нет необходимости, надо возбудить StopIteration
        '''
        if priority: return self.events[event].unshift(f)
        else:        return self.events[event].push(f)
    def removeHandler(self,event,f):
        ''' Удаление обработчика '''
        del self.events[event][f]
    def raiseEvent(self,event,*args):
        ''' Вызов зарегистрированных обработчиков '''
        for i in self.events[event].keys():
            try:
                # большинству обработчиков не понадобится менять передаваемое значение
                # а лишние "return args" будут загромождать код плагинов
                # пусть если None, то значение не меняется
                newargs = self.events[event][i](*args)
                if not newargs is None: args = newargs
            except StopIteration: break
